﻿using System;
using MySql.Data.MySqlClient;

namespace MySql.Simple.Mapper.Structures
{
    /// <summary>
    /// Represents a column in a database table
    /// </summary>
    public class Column
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="Column"/> class.
        /// </summary>
        public Column()
        {
            Signed = true;
        }

        /// <summary>
        /// Gets or sets the name.
        /// </summary>
        /// <value>The name.</value>
        public string Name { get; set; }

        /// <summary>
        /// Gets or sets the type.
        /// </summary>
        /// <value>The type.</value>
        public MySqlDbType Type { get; set; }

        /// <summary>
        /// Gets or sets the length.
        /// </summary>
        /// <value>The length.</value>
        public int Length { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether this <see cref="Column"/> is a primary key.
        /// </summary>
        /// <value><c>true</c> if [primary key]; otherwise, <c>false</c>.</value>
        public bool PrimaryKey { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether [auto increment].
        /// </summary>
        /// <value><c>true</c> if [auto increment]; otherwise, <c>false</c>.</value>
        public bool AutoIncrement { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether this <see cref="Column"/> is nullable.
        /// </summary>
        /// <value><c>true</c> if nullable; otherwise, <c>false</c>.</value>
        public bool Nullable { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether this column appears before any other in the table.
        /// </summary>
        /// <value><c>true</c> if this instance is first; otherwise, <c>false</c>.</value>
        public bool IsFirst { get; set; }

        /// <summary>
        /// Gets or sets the name of the column that precedes this column.
        /// </summary>
        /// <value>The after.</value>
        public string After { get; set; }

        /// <summary>
        /// Gets or sets the name of the table.
        /// </summary>
        /// <value>The name of the table.</value>
        public string TableName { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether this <see cref="Column"/> is signed.
        /// </summary>
        /// <value><c>true</c> if signed; otherwise, <c>false</c>.</value>
        public bool Signed { get; set; }

        /// <summary>
        /// Gets or sets the value of the column.
        /// </summary>
        /// <value>The value.</value>
        public object Value { get; set; }

        /// <summary>
        /// Gets or sets the name of the property that this column is mapped to.
        /// </summary>
        /// <value>The name of the property.</value>
        public string PropertyName { get; set; }

        /// <summary>
        /// Returns the database type as a string.
        /// </summary>
        /// <returns></returns>
        public string TypeAsString()
        {
            var type = Type.ToString().ToLower();

            if (type.StartsWith("int")) type = "int";
            if (type.StartsWith("uint")) type = "int";

            return type;
        }

        /// <summary>
        /// Returns the SQL fragment needed to create this column in a table.
        /// </summary>
        /// <returns></returns>
        public string ToDefinitionSql()
        {
            // Basic definition
            var sql = string.Format("`{0}` {1}", Name, TypeAsString());

            if (Type != MySqlDbType.Date &&
                Type != MySqlDbType.DateTime &&
                Type != MySqlDbType.Datetime &&
                Type != MySqlDbType.Double)
            {
                sql += string.Format("({0})", Length);
            }

            // Unsigned?
            if (!Signed) sql += " UNSIGNED";

            // Nullable?
            if (!Nullable) sql += " NOT NULL";

            // Auto increment?
            if (AutoIncrement && PrimaryKey) sql += " AUTO_INCREMENT";

            return sql;
        }

        /// <summary>
        /// Returns this column as a <see cref="MySqlParameter"/>
        /// </summary>
        /// <returns></returns>
        public MySqlParameter ToDbParameter()
        {
            return new MySqlParameter("?" + Name, Type) { Value = Value };
        }
    }
}
